%% Author: william
%% Created: 2011-7-18
%% Description: TODO: Add description to bogochat
-module(chat).

%%
%% Include files
%%

%%
%% Exported Functions
%%
-export([listen/1]).

%%
%% API Functions
%%
-define(TCP_OPTIONS, [list, {packet, 0}, {active, false}, {reuseaddr, true}]).

-record(player, {name=none, socket, mode}).


%%
%% Local Functions
%%

listen(Port) ->
	{ok, LSocket} = gen_tcp:listen(Port, ?TCP_OPTIONS),
	Pid = spawn(fun() -> maintain_clients([]) end),
	register(client_manager, Pid),
	do_accept(LSocket).

do_accept(LSocket) ->
	case gen_tcp:accept(LSocket) of
		{ok, Socket} ->
			spawn(fun() -> handle_client(Socket) end),
			client_manager ! {connect, Socket};
		{error, Reason} ->
			io:fwrite("Socket accept error: ~w~n", [Reason])
	end,
	do_accept(LSocket).

handle_client(Socket) ->
	case gen_tcp:recv(Socket, 0) of
		{ok, Data} ->
			client_manager ! {data, Socket, Data},
			handle_client(Socket);
		{error, closed} ->
			client_manager ! {disconnect, Socket}
	end.

maintain_clients(Players) ->
	io:fwrite("Playes:`n"),
	lists:foreach(fun(P) -> io:fwrite(">>> ~w~n", [P]) end, Players),
	receive
		{connect, Socket} ->
			Player = #player{socket=Socket, mode=connect},
			send_prompt(Player),
			io:fwrite("client connected: ~w~n", [Player]),
			NewPlayers = [Player | Players];
		{disconnect, Socket} ->
			Player = find_player(Socket, Players),
			io:fwrite("client disconnect: ~w~n", [Player]),
			NewsPlayers = lists:delete(Player, Players);
		{data, Socket, Data} ->
			Player = find_player(Socket, Players),
			NewPlayers = parse_data(Player, Players, Data),
			NewPlayer = find_player(Socket, NewPlayers),
			send_prompt(NewPlayer)
	end,
	maintain_clients(NewPlayers).

find_player(Socket, Players) ->
	{value, Player} = lists:keysearch(Socket, #player.socket, Players), 
	player.

delete_player(Player, Players) ->
	lists:keydelete(Player#player.socket, #player.socket, Players).

send_prompt(Player) ->
	case Player#player.mode of
		connect ->
			gen_tcp:send(Player#player.socket, "Name:");
		active ->
			ok
	end.

send_to_active(Prefix, Players, Data) ->
	ActivePlayers = lists:filter(fun(P) -> P#player.mode == acitve end, Players),
	lists:foreach(fun(P) -> gen_tcp:send(P#player.socket, Prefix ++ Data) end, ActivePlayers),
	ok.

parse_data(Player, Players, Data) ->
	case Player#player.mode of
		active ->
			send_to_active(Player#player.name ++ ": ", delete_player(Player,Players),Data),
			Players;
		connect ->
			UPlayer = Player#player{name=bogostrip(Data), mode=acitve},
			[UPlayer | delete_player(Player, Players)]
	end.

bogostrip(String) ->
	bogostrip(String, "/r/n/t ").

bogostrip(String, Chars) ->
	[Stripped|_Rest] = string:tokens(String, Chars),
	Stripped.
